#include "bib_Socket_Win.h"

extern CONFIG_EST config;

int inicializarWinsock(void){

	WSADATA wsaData;
	int error;
	char msj[7 + 1];
	
	if (error = WSAStartup(MAKEWORD(LOWBYTE, HIGHBYTE), &wsaData)){
		sprintf(msj, "(%d)", error);
		imprimirLog(ERROR, "Error al inicializar Winsock", msj);
		return EXIT_FAILURE;
	}
	
	imprimirLog(DEBUG, "Winsock inicializada correctamente", "");
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int finalizarWinsock(void){
	
	char msj[7 + 1];
	
	if (WSACleanup()){
		sprintf(msj, "(%d)", WSAGetLastError());
		imprimirLog(WARNING, "Error al finalizar Winsock", msj);
		return EXIT_FAILURE;
	}
	
	imprimirLog(DEBUG, "Winsock finalizada correctamente", "");
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int abrirSocket (SOCKET *miSock){
	
	char msj[7 + 1];
	
	if ((*miSock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET){
		sprintf(msj, "(%d)", WSAGetLastError());
		imprimirLog(ERROR, "socket:", msj);
		/*finalizarWinsock();*/
		return EXIT_FAILURE;
	}
	
	imprimirLog(DEBUG, "socket OK", "");
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int cerrarSocket(SOCKET miSock){
	
	char msj[7 + 1];
	
	if(closesocket(miSock)){
		sprintf(msj, "(%d)", WSAGetLastError());
		imprimirLog(WARNING, "closesocket:", msj);
		/*finalizarWinsock();*/
		return EXIT_FAILURE;
	}
	
	imprimirLog(DEBUG, "closesocket OK", "");
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int conectar(SOCKET miSock){
	struct sockaddr_in addrDestino;
	char msj[7 + 1];
	
	addrDestino.sin_family = AF_INET;
	addrDestino.sin_port = htons(config.puertoKSS);
	addrDestino.sin_addr.s_addr = inet_addr(config.IPKSS);
	memset(addrDestino.sin_zero, '\0', 8);
	
	if (connect(miSock, (struct sockaddr *) &addrDestino, sizeof(struct sockaddr)) == SOCKET_ERROR){
		sprintf(msj, "(%d)", WSAGetLastError());
		imprimirLog(ERROR, "connect:", msj);
		cerrarSocket(miSock);
		return EXIT_FAILURE;
	}
	
	imprimirLog(DEBUG, "connect OK", "");
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int sendall(SOCKET sock, char *buf, int *len){
	int bytesRestantes = *len;
	int n;
	int total = 0;	/* cantidad bytes enviados*/
	char msj[7 + 1];
	
	while (total < *len){
		n = send(sock, buf + total, bytesRestantes, 0);
		if (n == SOCKET_ERROR){
			sprintf(msj, "(%d)", WSAGetLastError());
			imprimirLog(ERROR, "send:", msj);
			break;
		}
		total += n;
		bytesRestantes -= n;
	}
	*len = total;
	return n == SOCKET_ERROR ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*=====================================================================================*/
int reciveall(SOCKET sock, char *buf, int *len, char *info){

	int bytesRestantes = *len;
	int n;
	int total = 0;	/*cantidad bytes recibidos*/
	char msj[7 + 1];
	
	*info = '\0';
	
	while (total < *len){
		n = recv(sock, buf + total, bytesRestantes, 0);
		
		if (n == SOCKET_ERROR){
			*info = FLAG_ERROR;
			sprintf(msj, "(%d)", WSAGetLastError());
			imprimirLog(ERROR, "recv:", msj);
			break;
		}
		
		if (!n){
			*info = FLAG_FIN;
			imprimirLog(ERROR, "recv:", "La maquina remota finalizo la conexion");
			break;
		}
		
		total += n;
		bytesRestantes -= n;
	}
	*len = total;
	return (n == SOCKET_ERROR || !n) ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*=====================================================================================*/
/*int obtenerMiIP(SOCKET miSock, char *miIP){
	struct sockaddr_in address;
	int len;
	
	len = sizeof(address);
	
	if (getsockname(miSock, (struct sockaddr *)&address, &len) < 0){
		imprimirLog(ERROR, "getsockname:", "No se pudo obtener ip y puerto del host");
		return EXIT_FAILURE;
	}
	strcpy(miIP, inet_ntoa(address.sin_addr));
	
	return EXIT_SUCCESS;
}*/
/*=====================================================================================*/
int enviarMensajeMPS(SOCKET sock, struct HEADER_MPS *header, char *payload){
	
	int len = sizeof(HEADER_MPS);
	
	if (sendall(sock, (char *) header, &len))
		return EXIT_FAILURE;
		
	if (header->payloadLength > 0)
		if (sendall(sock, payload, (int *) &(header->payloadLength)))
			return EXIT_FAILURE;
	
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int recibirMensajeMPS(SOCKET sock, struct HEADER_MPS *header, char *payload){
	
	char flag;
	int len = sizeof(HEADER_MPS);
	
	if (reciveall(sock, (char *) header, &len, &flag))
		return EXIT_FAILURE;

	if (header->payloadLength > 0)
		if (reciveall(sock, payload, (int *) &(header->payloadLength), &flag))
			return EXIT_FAILURE;
	
	return EXIT_SUCCESS;
}
/*=====================================================================================*/
int generarDescriptorID(char *descriptorID){

	int i;
	
	srand(time(NULL) + GetCurrentThreadId());
	
	for (i = 0; i < TAM_DESCRIPTOR_ID; i++)
		*(descriptorID + i) = rand() % ('Z' - 'A' + 1) + 'A';
		
	return EXIT_SUCCESS;
}